EC2 インスタンス一覧を特定の条件でフィルタリングしてから特定の項目を抽出した上で CSV 形式で出力してみた
コンバンハ、千葉(幸)です。
EC2 インスタンスの一覧を CSV 出力したい、というケースは稀によくあるかと思います。
そして、すべてのインスタンスを出力するのではなく、ステータスやインスタンスタイプなどの条件によってフィルタリングしたくなる時がしばしばあるでしょう。
さらには、必要なのはインスタンス ID や Name タグなどの特定の項目だけで、出力するのは必要最低限の項目に絞りたいという思いが去来することもあるのではないでしょうか。
取り立てて目新しいことは何もないですが、いざ AWS CLI で実際にやってみようとなった時に時間を要してしまったので、備忘も兼ねて記しておきます。
まとめ
かなり決め打ちの部分もありますが、基本形としては以下です。必要に応じてカスタマイズしてお使いください。
aws ec2 describe-instances\ --max-items 1000\ --filters\ Name=instance-state-name,Values=running\ Name=availability-zone,Values=ap-northeast-1a,ap-northeast-1d\ --query 'Reservations[].Instances[].{ InstanceId:InstanceId, InstanceType:InstanceType, Name:Tags[?Key==`Name`]|[0].Value, ASG:Tags[?Key==`aws:autoscaling:groupName`]|[0].Value }'\ --output json\ | jq -r ' ["Nameタグ","インスタンスID","インスタンスタイプ","ASG名"], ( .[] | [.Name, .InstanceId, .InstanceType ,.ASG]) | @csv'
変な改行挟まないでくれ、という場合はこちらを。
aws ec2 describe-instances --max-items 1000 --filters Name=instance-state-name,Values=running Name=availability-zone,Values=ap-northeast-1a,ap-northeast-1d --query 'Reservations[].Instances[].{ InstanceId:InstanceId, InstanceType:InstanceType, Name:Tags[?Key==`Name`]|[0].Value, ASG:Tags[?Key==`aws:autoscaling:groupName`]|[0].Value }' --output json | jq -r '["Nameタグ","インスタンスID","インスタンスタイプ","ASG名"], ( .[] | [.Name, .InstanceId, .InstanceType ,.ASG]) | @csv'
上記のコマンドは、ざっくり以下の条件を満たすものです。
- サーバーサイドのフィルタリング
- インスタンスが
Running
である - 所属 AZ が ap-northeast-1a | 1d である
- インスタンスが
- クライアントサイドのフィルタリング
- 以下項目のみ出力
- インスタンス ID
- インスタンスタイプ
- Name タグ
- AutoScalingGroup タグ
- 以下項目のみ出力
上記の出力結果を jq により CSV 形式に変換しています。 14 行目でヘッダーも指定しています。出力イメージは以下です。
"Nameタグ","インスタンスID","インスタンスタイプ","ASG名" "Test","i-047875da17caa9cc2","t2.micro", "MAKARONI","i-07856803079a58378","t3.small","MAKARONI-ASG" ....
ここでは標準出力にそのまま出力する形になっていますが、> ファイル名
でファイルに書き出したり、mac であれば| pbcopy
でクリップボードに貼り付けるなど、ご自由に処理してください。わたしは pbcopy パターンが最近のお気に入りです。
今回使用した AWS CLI のバージョンは以下です。
% aws --version aws-cli/2.2.29 Python/3.8.8 Darwin/19.6.0 exe/x86_64 prompt/off
サーバーサイドのフィルタリング
サーバーサイド、クライアントサイドという表現は以下から拝借しています。
ここでは--filters
オプションによるフィルタリングを指します。--filters
オプションは以下の形式で使用します。
Name=string,Values=string,string ...
[ { "Name": "string", "Values": ["string", ...] } ... ]
今回の例では前者の構文を用いています。instance-state-name
とavailability-zone
を指定していますが、他にもさまざまな項目で絞り込みを行えます。
詳細は CLI のコマンドリファレンスを参照してください。
クライアントサイドのフィルタリング
サーバーサイドのフィルタリングにより、対象のインスタンスを絞り込むことができました。続いてクライアントサイドのフィルタリング--query
により出力される項目を絞り込みます。
CLI リファレンスの例から引用したものですが、--query
なしの場合は以下のように大量の項目が返されます。
折り畳み
{ "Reservations": [ { "Groups": [], "Instances": [ { "AmiLaunchIndex": 0, "ImageId": "ami-0abcdef1234567890, "InstanceId": "i-1234567890abcdef0, "InstanceType": "t2.micro", "KeyName": "MyKeyPair", "LaunchTime": "2018-05-10T08:05:20.000Z", "Monitoring": { "State": "disabled" }, "Placement": { "AvailabilityZone": "us-east-2a", "GroupName": "", "Tenancy": "default" }, "PrivateDnsName": "ip-10-0-0-157.us-east-2.compute.internal", "PrivateIpAddress": "10.0.0.157", "ProductCodes": [], "PublicDnsName": "", "State": { "Code": 0, "Name": "pending" }, "StateTransitionReason": "", "SubnetId": "subnet-04a636d18e83cfacb", "VpcId": "vpc-1234567890abcdef0", "Architecture": "x86_64", "BlockDeviceMappings": [], "ClientToken": "", "EbsOptimized": false, "Hypervisor": "xen", "NetworkInterfaces": [ { "Attachment": { "AttachTime": "2018-05-10T08:05:20.000Z", "AttachmentId": "eni-attach-0e325c07e928a0405", "DeleteOnTermination": true, "DeviceIndex": 0, "Status": "attaching" }, "Description": "", "Groups": [ { "GroupName": "MySecurityGroup", "GroupId": "sg-0598c7d356eba48d7" } ], "Ipv6Addresses": [], "MacAddress": "0a:ab:58:e0:67:e2", "NetworkInterfaceId": "eni-0c0a29997760baee7", "OwnerId": "123456789012", "PrivateDnsName": "ip-10-0-0-157.us-east-2.compute.internal", "PrivateIpAddress": "10.0.0.157" "PrivateIpAddresses": [ { "Primary": true, "PrivateDnsName": "ip-10-0-0-157.us-east-2.compute.internal", "PrivateIpAddress": "10.0.0.157" } ], "SourceDestCheck": true, "Status": "in-use", "SubnetId": "subnet-04a636d18e83cfacb", "VpcId": "vpc-1234567890abcdef0", "InterfaceType": "interface" } ], "RootDeviceName": "/dev/xvda", "RootDeviceType": "ebs", "SecurityGroups": [ { "GroupName": "MySecurityGroup", "GroupId": "sg-0598c7d356eba48d7" } ], "SourceDestCheck": true, "StateReason": { "Code": "pending", "Message": "pending" }, "Tags": [], "VirtualizationType": "hvm", "CpuOptions": { "CoreCount": 1, "ThreadsPerCore": 1 }, "CapacityReservationSpecification": { "CapacityReservationPreference": "open" }, "MetadataOptions": { "State": "pending", "HttpTokens": "optional", "HttpPutResponseHopLimit": 1, "HttpEndpoint": "enabled" } } ], "OwnerId": "123456789012" "ReservationId": "r-02a3f596d91211712", } }
上記すべての情報が必要、というケースはなかなかないかと思いますので、適宜取捨選択しましょう。
今回の例では以下の形式で--query
を指定しています。
--query 'Reservations[].Instances[].{ InstanceId:InstanceId, InstanceType:InstanceType, Name:Tags[?Key==`Name`]|[0].Value, ASG:Tags[?Key==`aws:autoscaling:groupName`]|[0].Value }'\
:
の左側のラベルは任意のものを指定できます。
この状態で出力すると、以下のように結果が得られます。
[ { "InstanceId": "i-047875da17caa9cc2", "InstanceType": "t2.micro", "Name": "Test", "ASG": null }, { "InstanceId": "i-07856803079a58378", "InstanceType": "t3.small", "Name": "MAKARONI", "ASG": "MAKARONI-ASG" } ]
だいぶ見やすくなりましたがもう一息です。
jq による CSV 形式への変換
jq
も--query
と同じようにクライアントサイドでのフィルタリングに使用できますが、今回は CSV 形式への変換のみに使用しています。(--query
を使用せずjq
のみで完結できないかと考えたのですが、タグの指定の部分がどうにもうまくいきませんでした。)
以下の形式で指定しています。ヘッダーが不要な場合は2行目を削ってください。
| jq -r ' ["Nameタグ","インスタンスID","インスタンスタイプ","ASG名"], (.[] | [.Name, .InstanceId, .InstanceType ,.ASG]) | @csv'
この辺りは以下を大いに参考にしました。
おまけ
jq
による CSV 形式への変換をかまさずとも、アウトプットをtable
形式で指定するとそれなりにいい感じに出力してくれます。
% aws ec2 describe-instances\ --max-items 1000\ --filters # 任意のものを指定 --query 'Reservations[].Instances[].{ InstanceId:InstanceId, InstanceType:InstanceType, Name:Tags[?Key==`Name`]|[0].Value, ASG:Tags[?Key==`aws:autoscaling:groupName`]|[0].Value }'\ --output table ----------------------------------------------------------------------- | DescribeInstances | +----------------+----------------------+---------------+-------------+ | ASG | InstanceId | InstanceType | Name | +----------------+----------------------+---------------+-------------+ | None | i-047875da17caa9cc2 | t2.micro | Test | | MAKARONI-ASG | i-07856803079a58378 | t3.small | MAKARONI | +----------------+----------------------+---------------+-------------+
列がアルファベット順でソートされてしまうところが残念ですが、「とりあえず表の体裁に整っていればいい」という場合にはこちらの方がお手軽かと思います。
おまけ2
わたしは CSV をゴニョゴニョする時は Google スプレッドシートを使用するので、コマンド | pbcopy
でクリップボードにコピーするのが好きです。
貼り付け時に「テキストを列に分割」が選択できるので、それを押下します。
いい感じになりました。便利!
あとは好きなだけスプレッドシートの関数と戯れましょう。
終わりに
EC2 インスタンスの一覧を CSV で出力したい、という話でした。
昔はよく、マネジメントコンソール上で一覧を範囲選択してコピーしたものを Excel にぺたっと貼り付けてからズレを直す、という真心を込めた対応をしていました。
今回一覧を出力したい環境は全部で 700 台くらいあったので、ギリギリ真心が足りなくなるな、と思い AWS CLI で出力してみました。
フィルタリングや jq による CSV への変換は他のケースでも使えるかと思いますので、お役立ていただければ幸いです。
以上、 チバユキ (@batchicchi) がお送りしました。